// Copyright (c) 2008-2010, Arne Claus
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
// following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list of conditions and the following 
//   disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
//   disclaimer in the documentation and/or other materials provided with the distribution.
// - Neither the name Arne Claus nor the names of any contributors may be used to endorse or promote products
//   derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef __INCLUDED_CBL_EVENT_H__
#define __INCLUDED_CBL_EVENT_H__

#include "CBL_Debug.h"
#include "CBL_ReferencePtr.h"

#include <queue>
#include <vector>

CB_NAMESPACE_START

// -------------------------------------------------------------------------------------------------
//	CEvent
//	Basic event handling type. You can give an event a class and a type, so that compinations
//	like Class=Input -> Type=Keyboard are possible.
//	Events are ment to be passed to classes the at least implement the IListener interface.
// -------------------------------------------------------------------------------------------------

class CEvent
{
public:
	
	enum ReservedEventClasses
	{
		ClassTypeInvalid	= 0,
		ClassTypeState		= 1,
		ClassTypeInput		= 2
	};
	
public:
	
	CEvent();
	CEvent(uint8 _TypeClassId, uint16 _TypeId, int8 _Priority=0, void* _pData=NULL);
	
	// -------------------------------------------------------------------------------------------------
	
	template <typename TType>
	TType* GetData() const		{ return static_cast<TType*>(m_pData); }
	
	int16 GetPriority() const	{ return m_Priority; }
	uint16 GetType() const		{ return m_TypeId; }
	uint8 GetClassType() const	{ return m_TypeClassId; }
	bool IsNilEvent() const		{ return GetType() == 0; }
	
private:
	
	uint16	m_TypeId;
	int8	m_TypeClassId;
	int8	m_Priority;
	void	*m_pData;
};

// -------------------------------------------------------------------------------------------------

typedef CReferencePtr<CEvent> EventPtr;

// -------------------------------------------------------------------------------------------------
//	IListener
//	Baseclass for event listener classes.
// -------------------------------------------------------------------------------------------------

class IListener
{
public:
	virtual int32 Push(const EventPtr& _rEvent) = 0;
};

// -------------------------------------------------------------------------------------------------
//	CQueuedListener
//	Baseclass implementation for a gather-and-process listener. CQueuedListener store events on a
//	first come, first served basis and can either process a certain number or all stored events
//	on ProcessEvents().
//	You can overload OnProcessEvent() to react on the events processed in ProcessEvents()
// -------------------------------------------------------------------------------------------------

class CQueuedListener : public IListener
{
public:
	
	BASELIB_API virtual int32 Push(const EventPtr& _rEvent);
	
protected:
	
	CB_FORCEINLINE void CB_INLINE_ATTR Clear()						{ m_EventQueue.clear(); }
	CB_FORCEINLINE uint32 CB_INLINE_ATTR Size() const				{ return (uint32)m_EventQueue.size(); }
	CB_FORCEINLINE void CB_INLINE_ATTR Reserve(uint32 _QueueSize)	{ m_EventQueue.reserve(_QueueSize); }

	CB_FORCEINLINE void CB_INLINE_ATTR ProcessEvents(uint32 _MaxCount=0);
	
	virtual void OnProcessEvent(EventPtr& CB_UNUSED(_rEvent)) 		{ /* nothing by default */ }
	
private:
	
	std::vector<EventPtr> m_EventQueue;
};

// -------------------------------------------------------------------------------------------------
//	CPriorityListener
//	Baseclass implementation for a priority based listener approach.
//	Events will be sorted by priority on Push() and can be fetched bei Pop().
// -------------------------------------------------------------------------------------------------

class CPriorityListener : public IListener
{
public:
	
	BASELIB_API virtual int32 Push(const EventPtr& _rEvent);
	
protected:
	
	CB_FORCEINLINE void CB_INLINE_ATTR Clear()									{ while (!m_EventQueue.empty()) m_EventQueue.pop(); }
	CB_FORCEINLINE uint32 CB_INLINE_ATTR Size() const							{ return (uint32)m_EventQueue.size(); }
	CB_FORCEINLINE void CB_INLINE_ATTR Reserve(uint32 CB_UNUSED(_QueueSize))	{  Debug::Error("Not implemented."); }

	CB_FORCEINLINE EventPtr CB_INLINE_ATTR Pop();
	
private:
	
	struct FCompare
	{
		CB_FORCEINLINE bool CB_INLINE_ATTR operator() (EventPtr& _rLhs, EventPtr& _rRhs);
	};
	
	std::priority_queue<EventPtr, std::vector<EventPtr>, FCompare> m_EventQueue;
};

#include "CBL_Event.hpp"

CB_NAMESPACE_END

#endif

